package top.wshape1.shiziapi.gateway.config;

import jakarta.annotation.Resource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.reactive.EnableWebFluxSecurity;
import org.springframework.security.config.web.server.SecurityWebFiltersOrder;
import org.springframework.security.config.web.server.ServerHttpSecurity;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.server.SecurityWebFilterChain;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.reactive.CorsConfigurationSource;
import org.springframework.web.cors.reactive.UrlBasedCorsConfigurationSource;
import top.wshape1.shiziapi.gateway.filter.JwtTokenFilter;
import top.wshape1.shiziapi.gateway.security.SecurityContextRepository;

import java.time.Duration;

/**
 * @author Wshape1
 * @version 1.0
 * @description
 * @since 2023-08-23
 */

@Configuration
@EnableWebFluxSecurity
public class SecurityConfig {

//    @Resource
//    private ShiZiApiConfig shiZiApiConfig;

    @Resource
    private JwtTokenFilter jwtTokenFilter;

    @Resource
    private SecurityContextRepository securityContextRepository;

    @Bean
    public SecurityWebFilterChain standardSecurityFilterChain(ServerHttpSecurity http) {
        http
                .authorizeExchange(authorize -> authorize
                        .pathMatchers("/error").permitAll()
                        // 登录注册访问地址
                        .pathMatchers("/api/uaa/login",
                                "/api/uaa/forget/**",
                                "/api/uaa/reg/**",
                                "/api/uaa/oauth2/**",
                                "/api/mock/mock/u/**", // MOCK链接请求

                                // 预览项目 开放接口
                                "/api/project/doc/list", // 获取项目文档列表
                                "/api/project/project/name", // 获取项目文档名称
                                "/api/project/api/tag/list",
                                "/api/project/api/data",
                                "/api/project/rtf/content",
                                "/api/project/markdown/content",
                                "/api/project/mindmap/content",
                                "/api/project/like/isLike",  // 获取热门项目是否点赞，没有登录返回空
                                "/api/search/search/**",     // 获取热门项目等
                                "/api/project/read/**"      // 浏览项目相关
                        ).permitAll()
                        .pathMatchers("/login", "/logout").denyAll()
                        .anyExchange().authenticated()
                )
                .formLogin(ServerHttpSecurity.FormLoginSpec::disable)
                .logout(ServerHttpSecurity.LogoutSpec::disable)
                .csrf(ServerHttpSecurity.CsrfSpec::disable)
                .cors(cors -> cors.configurationSource(corsConfigurationSource()))
                .addFilterAfter(jwtTokenFilter, SecurityWebFiltersOrder.CORS)
                .securityContextRepository(securityContextRepository)
        ;

        return http.build();
    }

    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

    private CorsConfigurationSource corsConfigurationSource() {
        CorsConfiguration corsConfiguration = new CorsConfiguration();
//        corsConfiguration.setAllowedOriginPatterns(shiZiApiConfig.IP_WHITE_LIST);
        corsConfiguration.addAllowedOriginPattern("*");
        corsConfiguration.addAllowedHeader("*");
        corsConfiguration.addAllowedMethod("*");
        corsConfiguration.addExposedHeader("*");
        corsConfiguration.setAllowCredentials(true);
        corsConfiguration.setMaxAge(Duration.ofMinutes(1));

        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/**", corsConfiguration); //配置允许跨域访问的url
        return source;
    }

}
